package com.ll.microuser.user.sercvice.Impl;

import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ll.api.feign.PointFeign;
import com.ll.common.core.common.JwtUtils;
import com.ll.common.core.entity.User;
import com.ll.common.core.ex.BusinessException;
import com.ll.common.core.utils.TokenUtils;
import com.ll.common.core.utils.UserUtils;
import com.ll.common.neo4j.node.UserNode;
import com.ll.common.neo4j.relativship.InviteShip;
import com.ll.common.neo4j.utils.Neo4jUtils;
import com.ll.common.redis.utils.RedisUtils;
import com.ll.common.threadpool.ThreadPoolConfig;
import com.ll.microuser.user.mapper.UserMapper;
import com.ll.microuser.user.pojo.DTO.LoginDTO;
import com.ll.microuser.user.pojo.DTO.UserDTO;
import com.ll.microuser.user.pojo.VO.MyVO;
import com.ll.microuser.user.sercvice.IUserService;
import io.jsonwebtoken.Claims;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Service
public class UserServiceImpl implements IUserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    private TokenUtils tokenUtils;
    @Autowired
    private UserUtils userUtils;
    @Autowired
    private Neo4jUtils neo4jUtils;
    @Autowired
    private ThreadPoolExecutor threadPool;
    @Autowired
    private PointFeign pointFeign;
    /**
     * 注册/邀请新用户
     * 1)校验参数是否为空
     * 2)检验用户名/手机号数据重复
     * 3)是否有邀请码
     * @param userDTO
     */
    @Override
    public void register(UserDTO userDTO) {

        User user = new User();
        BeanUtils.copyProperties(userDTO,user);

        //手机号为null或'',或者长度不是11.-->格式不正确
        if (!StringUtils.hasText(userDTO.getPhone()) || userDTO.getPhone().length() != 11){
            throw new BusinessException("手机号格式不正确");
        }
        //判断密码
        if (!StringUtils.hasText(userDTO.getPassword())){
            throw new BusinessException("密码为空");
        }

        //TODO 验证码...
        if (!StringUtils.hasText(userDTO.getCode())){
            throw new BusinessException("验证码为空");
        }
        //不为空
        String code = redisUtils.getCacheObject(userDTO.getPhone());
        if (!StringUtils.hasText(code)){
            throw new BusinessException("验证码已失效");
        }
        if (!code.equals(userDTO.getCode())){
            throw new BusinessException("验证码错误");
        }
        //TODO 邀请码...
        /**
         * 1)注册时邀请码是别人提供的.
         * 2)根据邀请码查询邀请人的id.
         * 3)给pid赋值,重新生成新的自己的邀请码.
         */
        User parentuser;
        if (StringUtils.hasText(userDTO.getInviteCode())){//邀请码不为空
            parentuser = userMapper.selectOne(Wrappers.lambdaQuery(User.class)
                    .eq(User::getInviteCode, userDTO.getInviteCode()));

            if (ObjectUtils.isEmpty(parentuser)){
                throw new BusinessException("邀请码有误");
            }
            //邀请人id
            user.setPid(parentuser.getId());
            pointFeign.add(parentuser.getId(),1);

        } else {
            parentuser = null;
        }
        //生成新的邀请码
        String newInviteCode = RandomUtil.randomString(6);
        user.setInviteCode(newInviteCode);

        threadPool.execute(() -> {
            //neo4j================================
            try {
                Thread.sleep(30*1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            UserNode userNode = new UserNode();
            userNode.setId(user.getId());
            userNode.setUsername(user.getUsername());
            if (StringUtils.hasText(userDTO.getInviteCode())){
                UserNode parentNode = new UserNode();
                parentNode.setId(parentuser.getId());
                parentNode.setUsername(parentuser.getUsername());
                neo4jUtils.addNode(parentNode,userNode);
            }else {
                neo4jUtils.addNode(userNode);
            }
        });


        if(userMapper.exists( Wrappers.lambdaQuery(User.class)
                .eq(User::getPhone, userDTO.getPhone()))
        ){
            throw new BusinessException("手机号已存在");
        }
//        User user1 = userMapper.selectOne(Wrappers.lambdaQuery(User.class)
//                .eq(User::getUsername, userDTO.getUsername()));
//        if (ObjectUtils.isEmpty(user1)){
//            throw new BusinessException("用户名已存在");
//        }
        //用户名重复校验
        LambdaQueryWrapper<User> queryWrapper = Wrappers.lambdaQuery(User.class)
                .eq(User::getUsername, userDTO.getUsername());
        boolean exists = userMapper.exists(queryWrapper);//有则true,无则false
        if (exists){
            throw new BusinessException("用户名已存在");
        }

        userMapper.insert(user);
    }

    @Override
    public void getphone(String phone) {
        if(userMapper.exists( Wrappers.lambdaQuery(User.class)
                .eq(User::getPhone, phone))
        ){
            throw new BusinessException("手机号已存在");
        }
    }

    /**
     * 发送验证码
     * @param phone
     * @return
     */
    @Override
    public String sendCode(String phone) {
        if (!StringUtils.hasText(phone) || phone.length() != 11){
            throw new BusinessException("手机号格式不正确");
        }
        //模拟验证码,无法发送手机
        String code = RandomUtil.randomNumbers(4);
        System.out.println("手机验证码============>"+code);

        // TODO 将验证码存入redis中,并设置过期时间
        redisUtils.setCacheObject(phone,code,5, TimeUnit.MINUTES);
        return code;
    }

    @Override
    public String login(LoginDTO loginDTO) {
        // 校验已经通过@Validated 实现

        // 根据用户名查询
        User user = userMapper.selectOne(Wrappers.lambdaQuery(User.class).eq(User::getUsername, loginDTO.getUsername()));

        if (ObjectUtils.isEmpty(user)) {
            throw new BusinessException("用户名不存在!");
        }
        // 判断密码
        if (!user.getPassword().equals(loginDTO.getPassword())) {
            throw new BusinessException("密码不正确!");
        }

        // 创建令牌
        HashMap<String, Object> map = new HashMap<>();
        map.put("uid",user.getId());
        String token = jwtUtils.createToken(map);

        return token;
    }

    /**
     * 查询用户信息
     * @return
     */
    @Override
    public MyVO getInfo() {
        // 获取当前请求对象,解析令牌,获取token,从而获取其中数据
//        ServletRequestAttributes requestAttributes =(ServletRequestAttributes)  RequestContextHolder.getRequestAttributes();
//        HttpServletRequest request = requestAttributes.getRequest();
//        String token = request.getHeader("token");
//        Claims claims = jwtUtils.parseToken(token);
//        Integer uid = (Integer) claims.get("uid");
//        Integer uid = tokenUtils.getUserIdFromToken();
        Integer uid = userUtils.getUId();
        User user = userMapper.selectById(uid);

        MyVO myVO = new MyVO();
        BeanUtils.copyProperties(user,myVO);
        // 余额,积分,签到状态是0
        myVO.setSignFlag(0);
        myVO.setPoint(0);
        myVO.setBalance(0);

        return myVO;
    }

    @Override
    public void updateById(User user) {
        userMapper.updateById(user);
    }

}
